﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows;


using System.Windows.Controls;

using TJDevHouse.Starcraft.Game;

namespace TJDevHouse.Starcraft.MapAnalyser.MapDrawing
{
	/// <summary>
	/// Draws a map's terrain onto a supplied canvas.
	/// </summary>
	class TerrainMapLayer : MapLayer
	{

		Dictionary<String, SolidColorBrush> terrainBrushes = new Dictionary<String, SolidColorBrush>();


		public string MostCommonHash = "";

		public SolidColorBrush MostCommonBrush;

        public TerrainMapLayer()
            : base()
        {
            SetupTerrainBrushes();
        }

        private void SetupTerrainBrushes()
        {
            //define the brushes
            SolidColorBrush notwalkableLowGround = new SolidColorBrush(Colors.Black);
            SolidColorBrush walkableLowGroundBuildable = new SolidColorBrush(Colors.DarkGreen);
            SolidColorBrush walkableLowGroundNotBuildable = new SolidColorBrush(Colors.DarkOliveGreen);

            SolidColorBrush notwalkableHighGround = new SolidColorBrush(Colors.DimGray);
            SolidColorBrush walkableHighGroundBuildable = new SolidColorBrush(Colors.Indigo);
            SolidColorBrush walkableHighGroundNotBuildable = new SolidColorBrush(Colors.DarkSlateBlue);

            //allocate to specific hash
            terrainBrushes.Add(MakeColorHash(0, 0, 0), notwalkableLowGround);
            terrainBrushes.Add(MakeColorHash(1, 1, 0), walkableLowGroundBuildable);
            terrainBrushes.Add(MakeColorHash(0, 1, 0), walkableLowGroundBuildable);
            terrainBrushes.Add(MakeColorHash(1, 0, 0), walkableLowGroundNotBuildable);

            terrainBrushes.Add(MakeColorHash(0, 0, 1), notwalkableHighGround);
            terrainBrushes.Add(MakeColorHash(1, 1, 1), walkableHighGroundBuildable);
            terrainBrushes.Add(MakeColorHash(1, 0, 1), walkableHighGroundNotBuildable);

            //freeze them to save some resources
            foreach (SolidColorBrush b in terrainBrushes.Values)
            {
                b.Freeze();
            }
        }

		/// <summary>
		/// Runs through all the tiles, counts the number of each hash.
		/// 
		/// The hash with the most counts will be used as the bg color
		/// of the canvas to skip having to render those tiles.
		/// </summary>
		private void DoHashCount(MapDisplay display)
		{

			Dictionary<String, int> hashCount = new Dictionary<string, int>();
			foreach (WalkTile wt in display.Map.WalkTiles)
			{
				int walkable = wt.IsWalkable ? 1 : 0;
				int buildable = wt.IsBuildable ? 1 : 0;
				int height = wt.IsHighGround ? 1 : 0;

				string hash = MakeColorHash(walkable, buildable, height);

				if (!hashCount.ContainsKey(hash))
				{
					hashCount[hash] = 0;
				}
				hashCount[hash]++;
			}

			int highestValue = 0;
			KeyValuePair<string, int> highestPair = new KeyValuePair<string, int>();

			foreach (KeyValuePair<string, int> kvp in hashCount)
			{
				if (kvp.Value > highestValue)
				{
					highestPair = kvp;
					highestValue = kvp.Value;
				}
			}


			Console.WriteLine(highestPair.Key + " = " + highestPair.Value);

			MostCommonHash = highestPair.Key;
		}


		protected override void RenderLayer(MapDisplay display)
		{
			if (MostCommonHash == "")
			{
				DoHashCount(display);

			}

			Map map = display.Map;

			if (map == null)
			{
				return;
			}

			Rectangle currentRect = new Rectangle();
			int width = 0;
			bool doRender = true;

			string prevHash = "";
			foreach (WalkTile wt in map.WalkTiles)
			{

				int walkable = wt.IsWalkable ? 1 : 0;
				int buildable = wt.IsBuildable ? 1 : 0;
				int highGround = wt.IsHighGround ? 1 : 0;

				//reset the hash each row
				if (wt.X == 0)
				{
					prevHash = "";
				}


				string hash = MakeColorHash(walkable, buildable, highGround);


				if (hash == prevHash)
				{
					width++;
				}
				else
				{
					if (width > 0)
					{
						if (doRender)
						{
							width++;
							currentRect.Width = width * display.WalkTileSize;

							LayerCanvas.Children.Add(currentRect);
						}
					}

					if (hash == MostCommonHash)
					{
						if (MostCommonBrush == null)
						{
							MostCommonBrush = GetMapBackColorBrush(walkable, buildable, highGround);
						}
						doRender = false;
					}
					else
					{
						doRender = true;

						SolidColorBrush brush = GetMapBackColorBrush(walkable, buildable, highGround);
						currentRect = new Rectangle();
						currentRect.Fill = brush;
						currentRect.Stroke = brush;
						currentRect.Height = display.WalkTileSize;
						display.PositionElementByWalkTile(currentRect, wt.X, wt.Y);
						width = 1;

					}
				}

				prevHash = hash;


			}

			LayerCanvas.Background = MostCommonBrush;
			Console.WriteLine("Processed, now rendering...");

		}

		private String MakeColorHash(int walkable, int buildable, int height)
		{
			return walkable.ToString() + buildable.ToString() + height.ToString();
		}

		private SolidColorBrush GetMapBackColorBrush(int Walkable, int Buildable, int Height)
		{
			//optimise the drawing by forcing the reuse of brushes
			string hash = MakeColorHash(Walkable, Buildable, Height);

			if (terrainBrushes.ContainsKey(hash))
			{
				return terrainBrushes[hash];
			}

            Console.WriteLine("Making brush for " + hash);

			Color clr;
			byte grey;
			if (Walkable == 0)
			{
				grey = (byte)(Height * 30);
			}
			else
			{
				if (Buildable == 0)
				{
					grey = (byte)(((Height + 1) * 170) / 3);
				}
				else
				{
					grey = (byte)(((Height + 1) * 250) / 3);
				}
			}


			clr = Color.FromArgb(255, grey, grey, grey);

			SolidColorBrush brush = new SolidColorBrush(clr);
			brush.Freeze();

			terrainBrushes.Add(hash, brush);


			return brush;


		}
	}
}
